/*
 * Copyright 2006-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.martinimix.domain.order;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.martinimix.domain.account.Address;
import net.martinimix.domain.account.Customer;
import net.martinimix.domain.payment.Payment;
import net.martinimix.domain.payment.PaymentMethod;
import net.martinimix.domain.payment.PaymentMethodList;

/**
 * Provides an order bean.
 * 
 * @author Scott Rossillo
 *
 */
public class Order implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	private Customer customer;
	
	private Address billingAddress;
	private Address shippingAddress;
	
	private PaymentMethodList paymentMethods;
	private List payments;
	
	private OrderHeader orderHeader;
	private List orderLines;
	
	private double taxRate;
	
	private long createdBy;
	private long modifiedBy;
	
	private List plannedShipments;
	
	/**
	 * Constructs a new, empty order.
	 */
	public Order() {
		
		customer = new Customer();
		
		paymentMethods = new PaymentMethodList();
		payments = new ArrayList();
		
		billingAddress = new Address();
		shippingAddress = new Address();
		
		orderHeader = new OrderHeader();
		orderLines = new ArrayList();
		
		taxRate = 0.00D;
	}
	
	/**
	 * Adds the given order line to this order.
	 * 
	 * @param orderLine the <code>OrderLine</code> to add to this
	 * <code>Order</code>
	 */
	public void addOrderLine(OrderLine orderLine) {
		
		if(orderLine == null) {
			throw new IllegalArgumentException("Added [OrderLine] cannot be null!");
		}
		
		orderLines.add(orderLine);
	}
	
	/**
	 * Adds the given payment to this order.
	 * 
	 * @param payment the <code>Payment</code> to add to this order
	 */
	public void addPayment(Payment payment) {
		
		if(payment == null) {
			throw new IllegalArgumentException("Added [Payment] cannot be null!");
		}
		
		payments.add(payment);
		
	}

	/* -------------------------- */
	
	/**
	 * Returns the billing address for this order.
	 * 
	 * @return the billing <code>Address</code> for this order
	 */
	public Address getBillingAddress() {
		return billingAddress;
	}

	/**
	 * Sets the billing address for this order.
	 * 
	 * @param billingAddress the billing <code>Address</code>
	 * for this order
	 */
	public void setBillingAddress(Address billingAddress) {
		this.billingAddress = billingAddress;
		
		// set the order header bill to id
		if(billingAddress.getId() != null) {
			this.getOrderHeader().setBillToId(billingAddress.getId());
		} else {
			System.err.println("WARNING: Billing address id null for order [" + this.getOrderHeader().getId() + "] ");
		}
	}

	/**
	 * Returns the shipping address for this order.
	 * 
	 * @return the shipping <code>Address</code> for this order
	 */
	public Address getShippingAddress() {
		return shippingAddress;
	}

	/**
	 * Sets the shipping address for this order and its order lines.
	 * 
	 * @param shippingAddress the shipping <code>Address</code>
	 * for this order
	 */
	public void setShippingAddress(Address shippingAddress) {
		this.shippingAddress = shippingAddress;
		setOrderLineShipTo(shippingAddress);
	}
	
	/**
	 * Sets the ship to address for all order lines to the given address
	 * 
	 * @param address the ship to <code>Address</code> for this 
	 * <code>order</code>'s lines
	 */
	public void setOrderLineShipTo(Address address) {
		
		OrderLine orderLine;
		
		for(int i = 0; i < orderLines.size(); i++) {
			orderLine = (OrderLine) orderLines.get(i);
			orderLine.setShipToId(address.getId());
		}
	}

	
	/**
	 * Returns the customer for this order.
	 * 
	 * @return the <code>Customer</code> for this order
	 */
	public Customer getCustomer() {
		return customer;
	}
	
	/**
	 * Sets the customer for this order.
	 * 
	 * @param customer the <code>Customer</code> 
	 * for this order
	 */
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
	
	/**
	 * Finds the payment on this order for the given payment method.
	 * 
	 * @param paymentMethod the <code>PaymentMethod</code> whose 
	 * <code>Payment</code> should be returned
	 * 
	 * @return the <code>Payment</code> for the given <code>paymentMethod</code>
	 * if found; <code>null</code> otherwise
	 */
	public Payment findPayment(PaymentMethod paymentMethod) {
		
		Payment payment;
		
		for(Iterator it = payments.iterator(); it.hasNext(); ) {
			
			payment = (Payment) it.next();
			if(payment.getPaymentTypeId().longValue() == paymentMethod.getId().longValue()) {
				return payment;
			}
		}
		
		return null;
	}

	/**
	 * Returns a list of payments for this order.
	 * 
	 * @return a <code>List</code> of payments for this order
	 */
	public List getPayments() {
		return payments;
	}

	/**
	 * Sets the payments for this order
	 * 
	 * @param payments the <code>List</code> of <code>Payment</code>s
	 * for this order 
	 */
	public void setPayments(List payments) {

		if(payments != null) {
			for(Iterator it = payments.iterator(); it.hasNext(); ) {
				if( !(it.next() instanceof Payment) ) {
					throw new IllegalArgumentException("All [payments] must be instances of [Payment]!");
				}
			}
		}

		this.payments = payments;
	}

	public PaymentMethodList getPaymentMethods() {
		return paymentMethods;
	}

	public void setPaymentMethods(PaymentMethodList paymentMethods) {
		this.paymentMethods = paymentMethods;
	}

	public List getPlannedShipments() {
		return plannedShipments;
	}

	public void setPlannedShipment(List plannedShipments) {
		this.plannedShipments = plannedShipments;
	}

	public OrderHeader getOrderHeader() {
		return orderHeader;
	}

	public void setOrderHeader(OrderHeader orderHeader) {
		this.orderHeader = orderHeader;
	}

	/**
	 * Returns the order lines for this order.
	 * 
	 * @return a <code>List</code> containing the 
	 * <code>OrderLine</code>s for this order
	 */
	public List getOrderLines() {
		return orderLines;
	}

	/**
	 * Sets the order lines for this order.
	 * 
	 * @param orderLines <code>List</code> containing the 
	 * <code>OrderLine</code>s for this order; may not be <code>null</code>
	 */
	public void setOrderLines(List orderLines) {
		
		if(orderLines == null) {
			throw new IllegalArgumentException("[OrderLine]s cannot be null!");
		}
		
		this.orderLines = orderLines;
	}


	/**
	 * Returns the tax rate percentage for this order.
	 * 
	 * @return the tax rate for this order
	 */
	public double getTaxRate() {
		return taxRate;
	}

	/**
	 * Sets the tax rate (percent) for this order.
	 * 
	 * @param taxRate the tax rate for this order
	 */
	public void setTaxRate(double taxRate) {
		this.taxRate = taxRate;
	}

	public long getCreatedBy() {
		return createdBy;
	}

	public void setCreatedBy(long createdBy) {
		this.createdBy = createdBy;
	}

	public long getModifiedBy() {
		return modifiedBy;
	}

	public void setModifiedBy(long modifiedBy) {
		this.modifiedBy = modifiedBy;
	}
	
}
